/*
 * Copyright (c) 2015-2018 Sfkj Science And Technology Co.,Ltd.
 * All Rights Reserved.
 * This software is the confidential and proprietary information of
 * Sfkj Science And Technology Co.,Ltd.
 * ("Confidential Information").You shall not
 * disclose such Confidential Information and shall use it only in
 * accordance with the terms of the license agreement you entered into
 * with Sfkj.
 */
package com.sfkj.walk.axon.web;

import com.sfkj.walk.SystemException;
import com.sfkj.walk.axon.web.dto.CommandDto;
import com.sfkj.walk.axon.web.dto.CommandResultDto;
import org.axonframework.commandhandling.TargetAggregateIdentifier;
import org.axonframework.commandhandling.callbacks.FutureCallback;
import org.axonframework.commandhandling.gateway.CommandGateway;
import org.axonframework.common.IdentifierFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

import java.lang.reflect.Field;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;

import static org.axonframework.common.ReflectionUtils.fieldsOf;
import static org.axonframework.common.ReflectionUtils.getFieldValue;

/**
 * 动态命令调用
 */
public abstract class AbstractCommandGatewayController<C> {
    @Autowired
    private CommandGateway commandGateway;

    @PostMapping
    public CommandResultDto commandGateway(@RequestBody CommandDto<C> commandDto) {
        Class<?> responseType = responseType();

        C command = commandDto.getPayload();

        handleIdentifierNull(command);

        CompletableFuture future = commandGateway.send(command);
        if (getNow()) {
            CommandResultDto dto = new CommandResultDto();
            dto.setResult(((FutureCallback) future).getResult());
            return dto;
        }
        return null;
    }

    /**
     * 考虑新建，为 Null 缺省动态赋值
     *
     * @param command
     */
    private void handleIdentifierNull(Object command) {
        for (Field f : fieldsOf(command.getClass())) {
            if (f.isAnnotationPresent(TargetAggregateIdentifier.class)) {
                String id = Optional.ofNullable(getFieldValue(f, command))
                        .map(Object::toString).orElse(IdentifierFactory.getInstance().generateIdentifier());
                try {
                    f.set(command, id);
                    return;
                } catch (IllegalAccessException e) {
                    throw new SystemException("ID设置失败");
                }
            }
        }
    }

    protected Class responseType() {
        return null;
    }

    protected boolean getNow() {
        return true;
    }

}
